﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Nextropia.C2Manager.C2API
{
    /// <summary>
    /// represents a position in a system; a position can be the result of multiple, cummulative buy/sell signals
    /// </summary>
    public class Position
    {
        /// <summary>
        /// the symbol of the security contained in this position
        /// </summary>
        public string Symbol {get;set;}

        /// <summary>
        /// indicates the security type of the current position
        /// </summary>
        public SecurityType SecurityType { get; set; }

        /// <summary>
        /// time when the position was first opened
        /// </summary>
        public DateTime Opened { get; set; }

        /// <summary>
        /// time when the position was last closed
        /// </summary>
        public DateTime Closed { get; set; }

        /// <summary>
        /// quantity this position was initially opened with
        /// </summary>
        public decimal QuantityOpened { get; set; }

        /// <summary>
        /// quantity closed in this position so far
        /// </summary>
        public decimal QuantityClosed { get; set; }

        /// <summary>
        /// currently open quantity
        /// </summary>
        public decimal Quantity { get { return QuantityOpened - QuantityClosed; } }

        /// <summary>
        /// average price this position was opened at
        /// </summary>
        public decimal OpenPrice { get; set; }

        /// <summary>
        /// the monetary value of each quantity unit in this position
        /// </summary>
        /// <remarks>
        /// this value is normally 1 for equities, but can be a multiple (e.g. 10,000)
        /// for securities such as options, futures, or forex lots
        /// </remarks>
        public decimal PointValue { get; set; }

        /// <summary>
        /// the most recent price per unit of quantity
        /// </summary>
        /// <remarks>
        /// the last price is not guaranteed to be recent and is normally delayed
        /// at least several minutes
        /// </remarks>
        public Price LastPrice { get; set; }

        /// <summary>
        /// the total realized and unrealized profit in this position
        /// </summary>
        /// <remarks>
        /// This value is affected by LastPrice and may be based on a delayed price;
        /// negative values indicate a loss
        /// </remarks>
        public decimal Profit
        {
            get { return (LastPrice.Last - OpenPrice) * Math.Abs(Quantity) * PointValue; }
        }

        /// <summary>
        /// the trading system this position belongs to
        /// </summary>
        public TradingSystem System { get; private set; }

        /// <summary>
        /// default constructor taking the parent TradingSystem as a parameter
        /// </summary>
        /// <remarks>
        /// the position is NOT automatically added to the system's Positions collection
        /// </remarks>
        /// <seealso cref="TradingSystem.Positions"/>
        /// <param name="system"></param>
        public Position(TradingSystem system)
        {
            System = system;
            LastPrice = new Price();
        }

        internal Position(TradingSystem system, XmlNode node) : this(system)
        {

            Symbol = node.SelectSingleNode("symbol").InnerText;
            SecurityType = (SecurityType)Enum.Parse(typeof(SecurityType), node.SelectSingleNode("instrument").InnerText, true);
            Opened = C2Service.SafeParseDate(node.SelectSingleNode("positionOpened").InnerText);
            QuantityOpened = C2Service.SafeParseDecimal(node.SelectSingleNode("quantOpened").InnerText);
            QuantityClosed = C2Service.SafeParseDecimal(node.SelectSingleNode("quantClosed").InnerText);
            OpenPrice = C2Service.SafeParseDecimal(node.SelectSingleNode("entryPrice").InnerText);
            PointValue = C2Service.SafeParseDecimal(node.SelectSingleNode("pointValue").InnerText);
            LastPrice = new Price(node.SelectSingleNode("quote"));

            string side = node.SelectSingleNode("side").InnerText;

            switch (side)
            {
                case "long":
                    QuantityOpened = Math.Abs(QuantityOpened);
                    QuantityClosed = Math.Abs(QuantityClosed);
                    break;
                case "short":
                    QuantityOpened = -Math.Abs(QuantityOpened);
                    QuantityClosed = -Math.Abs(QuantityClosed);
                    break;
                default:
                    throw new Exception("Invalid value in <side> node (expected 'long' or 'short'): " + node.OuterXml);
            }
        }
    }
}
